#include "fd_manager_ddk.h"
#include <unistd.h>
#include <cerrno>
#include "securec.h"
#include "common/debug/log.h"
#include <dlfcn.h>
#include "sys/mman.h"

using namespace std;
using namespace ge;

namespace hiai {
using namespace error;
bool g_isInited = false;
FdManagerItfDef romItf_;
std::vector<FdManagerClientSymbol> symbols_{{reinterpret_cast<void**>(&romItf_.createFd), "CreateAshmemRegionFd"}};
int g_fd = 0;
map<int, void*> g_addrMap;

FdManager::~FdManager()
{
    symbols_.clear();
}

Status LoadRomSymbols(void* handle)
{
    void* func = nullptr;
    for (FdManagerClientSymbol& symbol : symbols_) {
        func = dlsym(handle, symbol.funcName);
        if (func == nullptr) {
            FMK_LOGE("func is nullptr");
            return FAILURE;
        }
        *symbol.funcPtr = func;
    }

    return SUCCESS;
}

Status OpenClient()
{
    if (g_isInited) {
        FMK_LOGW("libai_client has been dlopened!");
        return SUCCESS;
    }

    romItf_.mhandle = dlopen("libai_client_stub_ddk.so", RTLD_LAZY);

    if (romItf_.mhandle == nullptr) {
        g_isInited = true;
        return FAILURE;
    }

    if (LoadRomSymbols(romItf_.mhandle) != SUCCESS) {
        FMK_LOGE("LoadRomSymbol FAILURE");
        return FAILURE;
    }
    g_isInited = true;
    return SUCCESS;
}

int32_t FdManager::CreateFd(const char *name, size_t size)
{
    return g_fd++;
}

int32_t FdManager::DestroyFd(size_t fd)
{
    auto it = g_addrMap.find(fd);
    if (it != g_addrMap.end()) {
        delete[] (uint8_t*)it->second;
        g_addrMap.erase(it->first);
        return 0;
    }
    return 0;
}

int32_t FdManager::Mmap(void** addr, int64_t fd, uint64_t size)
{
    auto it = g_addrMap.find(fd);
    if (it != g_addrMap.end()) {
        *addr = it->second;
        return 0;
    }

    *addr = new uint8_t[size];
    g_addrMap[fd] = *addr;
    return 0;
}

int32_t FdManager::Unmap(void* addr, uint64_t size)
{
    // Free memory in DestroyFd
    return 0;
}

int32_t FdManager::CreateFdAndFlush(const char *name, size_t size, const void *srcAddr)
{
    int fd = FdManager::CreateFd(name, size);
    if (fd < 0) {
        printf("Allocate hidl request CreateFd failed.");
        return -1;
    }

    void *addr = nullptr;
    int32_t res = FdManager::Mmap(&addr, fd, size);
    if (res!= 0){
        FdManager::DestroyFd(fd);
        printf("Allocate memcpy_s failed.");
        return -1;
    }
    memcpy_s(addr, size, srcAddr, size);
    return fd;
}
} // namespace ge
